package com.giggle.nacos.registry.dubbo;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.common.URL;

import java.util.Objects;

/**
 * @author guozichen
 * @ClassName:
 * @Description: (这里用一句话描述累的作用)
 * @date 2020/8/26 17:55
 */
public class NacosServiceName {
    public static final String NAME_SEPARATOR = ":";
    public static final String VALUE_SEPARATOR = ",";
    public static final String WILDCARD = "*";
    public static final String DEFAULT_PARAM_VALUE = "";
    private static final int CATEGORY_INDEX = 0;
    private static final int SERVICE_INTERFACE_INDEX = 1;
    private static final int SERVICE_VERSION_INDEX = 2;
    private static final int SERVICE_GROUP_INDEX = 3;
    private String category;
    private String serviceInterface;
    private String version;
    private String group;
    private String value;

    public NacosServiceName() {
    }

    public NacosServiceName(URL url) {
        this.serviceInterface = url.getParameter("interface");
        this.category = this.isConcrete(this.serviceInterface) ? "providers" : url.getParameter("category");
        this.version = url.getParameter("version", "");
        this.group = url.getParameter("group", "");
        this.value = this.toValue();
    }

    public NacosServiceName(String value) {
        this.value = value;
        String[] segments = StringUtils.splitPreserveAllTokens(value, ":");
        this.category = segments[0];
        this.serviceInterface = segments[1];
        this.version = segments[2];
        this.group = segments[3];
    }

    public static NacosServiceName valueOf(URL url) {
        return new NacosServiceName(url);
    }

    public boolean isConcrete() {
        return this.isConcrete(this.serviceInterface) && this.isConcrete(this.version) && this.isConcrete(this.group);
    }

    public boolean isCompatible(NacosServiceName concreteServiceName) {
        if (!concreteServiceName.isConcrete()) {
            return false;
        } else if (!StringUtils.equals(this.category, concreteServiceName.category) && !ArrayUtils.contains(StringUtils.splitPreserveAllTokens(this.category, ","), concreteServiceName.category)) {
            return false;
        } else if (!StringUtils.equals(this.serviceInterface, concreteServiceName.serviceInterface)) {
            return false;
        } else if (this.isWildcard(this.version)) {
            return true;
        } else if (this.isWildcard(this.group)) {
            return true;
        } else if (!StringUtils.equals(this.version, concreteServiceName.version) && !this.matchRange(this.version, concreteServiceName.version)) {
            return false;
        } else {
            return StringUtils.equals(this.group, concreteServiceName.group) || this.matchRange(this.group, concreteServiceName.group);
        }
    }

    private boolean matchRange(String range, String value) {
        if (StringUtils.isBlank(range)) {
            return true;
        } else if (!this.isRange(range)) {
            return false;
        } else {
            String[] values = StringUtils.split(range, ",");
            return ArrayUtils.contains(values, value);
        }
    }

    private boolean isConcrete(String value) {
        return !this.isWildcard(value) && !this.isRange(value);
    }

    private boolean isWildcard(String value) {
        return "*".equals(value);
    }

    private boolean isRange(String value) {
        if (StringUtils.contains(value, ",")) {
            String[] values = StringUtils.split(value, ",");
            return ArrayUtils.getLength(values) > 1;
        } else {
            return false;
        }
    }

    public String getCategory() {
        return this.category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getServiceInterface() {
        return this.serviceInterface;
    }

    public void setServiceInterface(String serviceInterface) {
        this.serviceInterface = serviceInterface;
    }

    public String getVersion() {
        return this.version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getGroup() {
        return this.group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public String getValue() {
        if (this.value == null) {
            this.value = this.toValue();
        }

        return this.value;
    }

    private String toValue() {
        return this.category + ":" + this.serviceInterface + ":" + this.version + ":" + this.group;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (!(o instanceof NacosServiceName)) {
            return false;
        } else {
            NacosServiceName that = (NacosServiceName)o;
            return Objects.equals(this.getValue(), that.getValue());
        }
    }

    @Override
    public int hashCode() {
        return Objects.hash(new Object[]{this.getValue()});
    }

    @Override
    public String toString() {
        return this.getValue();
    }
}

